# -*- coding: utf-8 -*-
# created on 2017/2/15

from mathsolver.functions.base import *
from sympy import *
from mathsolver.functions.mathematica.mathematicaSolve import MathematicaSolve
from mathsolver.functions.zhixian.fangcheng import PointOnGraph
from mathsolver.functions.yuanzhui.property import OvalCoeffs, OvalAbc
import itertools
from mathsolver.functions.yuan.fangcheng import YuanFangCheng005


class ComputeArea(BaseFunction):
    def solver(self, *args):
        p1, p2, p3 = args[0].value
        x1, y1 = self.search(p1).sympify()
        x2, y2 = self.search(p2).sympify()
        x3, y3 = self.search(p3).sympify()

        area = Abs(((x3 - x1) * (y2 - y1) - (x2 - x1) * (y3 - y1)) / 2)
        # symbols = area.free_symbols
        # unknown_symbols = set(symbols).difference([Symbol("x"),Symbol("y")])
        self.steps.append(["%s面积为：" % args[0].printing(), ""])
        output = BasePoly(area)
        # if unknown_symbols:
        #     ans = self.search_multiple(unknown_symbols)
        #     if isinstance(ans, FiniteSet):
        #         for values in ans:
        #             if isinstance(values, (tuple, Tuple)):
        #                 symbol_value = dict([(sym,v) for sym, v in zip(unknown_symbols,values)])
        #             else:
        #                 symbol_value = {list(unknown_symbols)[0]:values}
        #
        #             f = area.subs(symbol_value)
        #             if f != 0:
        #                 self.steps.append([latex(f),""])
        #                 output = BasePoly(f)
        #                 self.output.append(output)
        #     else:
        #         self.steps.append([latex(area),""])
        #         self.output.append(output)
        # else:
        self.steps.append([new_latex(area), ""])
        self.output.append(output)

        assert self.steps
        self.label.add("已知三点求三角形面积")
        return self


class TuoYuanDuanDian(BaseFunction):
    def solver(self, *args):
        x_coeff, y_coeff = args[0].sympify()
        text = args[1]
        if "短轴" in text:
            pp = BasePoint({"name": "", "value": [0, sqrt(y_coeff)]})
        elif "长轴" in text:
            pp = BasePoint({"name": "", "value": [sqrt(x_coeff), 0]})
        elif "左" in text and "右" in text:
            pp = BasePoints([{"name": "", "value": [-sqrt(x_coeff), 0]}, {"name": "", "value": [sqrt(x_coeff), 0]}])
        elif "上" in text and "下" in text:
            pp = BasePoints([{"name": "", "value": [0, sqrt(y_coeff)]}, {"name": "", "value": [0, -sqrt(y_coeff)]}])
        elif "左" in text:
            pp = BasePoint({"name": "", "value": [-sqrt(x_coeff), 0]})
        elif "右" in text:
            pp = BasePoint({"name": "", "value": [sqrt(x_coeff), 0]})
        elif "上" in text:
            pp = BasePoint({"name": "", "value": [0, sqrt(y_coeff)]})
        elif "下" in text:
            pp = BasePoint({"name": "", "value": [0, -sqrt(y_coeff)]})
        else:
            raise ValueError()

        self.output.append(pp)
        self.label.add("求椭圆的端点")
        return self


class ShuangQuDuanDian(BaseFunction):
    def solver(self, *args):
        x_coeff, y_coeff, _ = args[0].sympify()
        text = args[1]
        if "左右" in text:
            pp = BasePoints([{"name": "", "value": [-x_coeff, 0]}, {"name": "", "value": [x_coeff, 0]}])
        elif "左" in text:
            pp = BasePoint({"name": "", "value": [-x_coeff, 0]})
        elif "右" in text:
            pp = BasePoint({"name": "", "value": [x_coeff, 0]})
        else:
            raise ValueError()

        self.output.append(pp)
        self.label.add("求双曲线的端点")
        return self


class CoorSymstem(BaseFunction):
    def solver(self, *args):
        self.output.append(BasePoint({"name": "O", "value": [0, 0]}))
        return self


class GraphIntersectAxis(BaseFunction):
    def solver(self, *args):
        eq = args[0].sympify()
        points = []
        ans1 = MathematicaSolve().solver(BaseEqs([eq, ["x", "0"]])).output[0].value
        for value in ans1.values()[0]:
            points.append({"name": "", "value": value.args})

        ans2 = MathematicaSolve().solver(BaseEqs([eq, ["y", "0"]])).output[0].value
        for value in ans2.values()[0]:
            points.append({"name": "", "value": value.args})

        self.output.append(BasePoints(points))
        self.label.add("图像和坐标轴交点")
        return self


class PointsOnGraph(BaseFunction):
    def solver(self, *args):
        points, graph = args
        f1, f2 = graph.sympify()
        eqs = []
        for xx, yy in points.sympify():
            symbol_value = {Symbol("x"): xx, Symbol("y"): yy}
            eqs.append([f1.subs(symbol_value), f2.subs(symbol_value)])

        self.output.append(BaseEqs(eqs))
        self.label.add("点在图像上")
        return self


class LinePosition(BaseFunction):
    def get_vector(self, ll):
        x1, y1 = self.search(ll.value[0]).sympify()
        x2, y2 = self.search(ll.value[1]).sympify()
        return y2 - y1, x2 - x1

    def solver(self, *args):
        line1, line2 = args[:2]
        x1, y1 = self.get_vector(line1)
        x2, y2 = self.get_vector(line2)
        self.output.append(BaseEq([x1 * x2 + y1 * y2, 0]))
        self.label.add("两线段垂直")
        return self


class TwoOvalFocusPoints(BaseFunction):
    def solver(self, *args):
        points = args[0]
        symmetry_point = args[1].sympify()
        x_coeff, y_coeff = args[2].sympify()

        if x_coeff.free_symbols and y_coeff.free_symbols:
            assert str(x_coeff) == "a**2" and str(y_coeff) == "b**2"
            a = Symbol("a")
            b = Symbol("b")
        else:
            a = sqrt(x_coeff)
            b = sqrt(y_coeff)

        c = sqrt(a ** 2 - b ** 2)

        left_point = [symmetry_point[0] - c, symmetry_point[1]]
        right_point = [symmetry_point[0] + c, symmetry_point[1]]
        names = [obj.name for obj in points.objs]

        self.output.append(BasePoint({"name": names[0], "value": left_point}))
        self.output.append(BasePoint({"name": names[1], "value": right_point}))
        self.label.add("椭圆的焦点")
        return self


class TwoHyperbolaFocusPoints(BaseFunction):
    def solver(self, *args):
        points = args[0]
        symmetry_point = args[1].sympify()
        x_coeff, y_coeff = args[2].sympify()

        if x_coeff.free_symbols and y_coeff.free_symbols:
            if str(x_coeff) == "a**2" and str(y_coeff) == "-b**2":
                a = Symbol("a")
                b = Symbol("b")
            else:
                a = sqrt(x_coeff)
                b = sqrt(-y_coeff)
        else:
            a = sqrt(x_coeff)
            b = sqrt(-y_coeff)

        c = sqrt(a ** 2 + b ** 2)

        left_point = [symmetry_point[0] - c, symmetry_point[1]]
        right_point = [symmetry_point[0] + c, symmetry_point[1]]
        names = [obj.name for obj in points.objs]

        p1 = BasePoint({"name": names[0], "value": left_point})
        p2 = BasePoint({"name": names[1], "value": right_point})
        self.output.append(p1)
        self.output.append(p2)
        self.steps.append(["由双曲线焦点公式得 %s %s" % (p1.printing(), p2.printing()), ""])
        self.label.add("双曲线的焦点")
        return self


class QuadraArea(BaseFunction):
    def sub_area(self, p1, p2):
        x1, y1 = self.search(p1).sympify()
        x2, y2 = self.search(p2).sympify()
        return x1 * y2 - x2 * y1

    def solver(self, *args):
        name = args[0].value.replace("*", "")
        area = sympify("0")
        for p1, p2 in zip(name, name[1:]):
            area += self.sub_area(p1, p2)

        area = Abs(area) / 2
        self.output.append(BasePoly(area))
        # unknown_symbols = area.free_symbols
        # ans = self.search_multiple(unknown_symbols)
        # print len(ans)
        self.label.add("求四边形面积")
        return self


class PointsOnOneYuan(BaseFunction):
    def solver(self, *args):
        points, yuan = args
        f1, f2 = yuan.sympify()
        eqs = []
        for pp in points.sympify():
            symbol_value = {Symbol("x"): pp[0], Symbol("y"): pp[1]}
            eqs.append([f1.subs(symbol_value), f2.subs(symbol_value)])

        obj = BaseEqs(eqs)
        self.steps.append(["设%s在同一圆上" % points.printing(), ""])
        self.steps.append([obj.printing(), ""])
        self.output.append(obj)
        self.label.add("四点共圆")
        return self


class JiaoJu(BaseFunction):
    def solver(self, *args):
        a, b = args[0].sympify()
        self.output.append(BasePoly(2 * sqrt(a - b)))
        self.label.add("双曲线的焦距")
        return self


class PaoWuDingDian(BaseFunction):
    def solver(self, *args):
        self.output.append(BasePoint({'name': "", "value": [0, 0]}))
        self.label.add("抛物线的顶点")
        return self


class YuanYuanXinPoint(BaseFunction):
    def solver(self, *args):
        yuan, r, pp = args[:3]
        p1, p2 = pp.sympify()
        yuan.value = ["(x-%s)**2 + (y-%s)**2" % (str(p1), str(p2)), str(r.sympify() ** 2)]
        self.output.append(yuan)
        return self


class TuoYuanJiaoJu(BaseFunction):
    def solver(self, *args):
        a, b, c = args[0].value
        self.output.append(BasePoly(2 * c))
        self.label.add("椭圆的焦距")
        return self


class PaoWuDuiChengZhou(BaseFunction):
    def solver(self, *args):
        self.output.append(BaseZhiXian({"name": "", "value": ["y", "0"]}))
        self.label.add("抛物线的对称轴")
        return self


class TuoYuanZhunXian(BaseFunction):
    def solver(self, *args):
        a, b, c = args[0].value
        if "右" in args[1]:
            self.output.append(BaseEq(["x", a ** 2 / c]))
        elif "左" in args[1]:
            self.output.append(BaseEq(["x", -a ** 2 / c]))
        else:
            self.output.append(
                BaseZhiXians([{"name": "", "value": ["x", -a ** 2 / c]}, {"name": "", "value": ["x", a ** 2 / c]}]))
        self.label.add("椭圆的准线")
        return self


class YuanZhiJingIsLine(BaseFunction):
    def solver(self, *args):
        line_name = args[0].name
        value = args[1].sympify()

        point1 = self.search(line_name[0])
        point2 = self.search(line_name[1])
        p1 = point1.sympify()
        p2 = point2.sympify()
        eq1 = [(p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2, (2 * value) ** 2]

        eq2 = PointOnGraph().solver(point1, args[2]).output[0].value
        eq3 = PointOnGraph().solver(point2, args[2]).output[0].value
        self.output.append(BaseEqs([eq1, eq2, eq3]))
        self.label.add("线段是圆的直径")
        return self


class TriangleZhouChang(BaseFunction):
    def solver(self, *args):
        tuoyuan = [value for _, value in self.known.items() if isinstance(value, BaseTuoYuan)]
        if tuoyuan:
            step1 = OvalCoeffs().solver(tuoyuan[0])
            step2 = OvalAbc().solver(*step1.output).output[0]
            self.output.append(BasePoly(4 * step2.value[0]))
        else:
            points = [self.search(nn).sympify() for nn in args[0].value]
            distances = []
            for p1, p2 in itertools.combinations(points, 2):
                dis = ((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2).simplify()
                distances.append(sqrt(dis))
            self.output.append(BasePoly(Add._from_args(distances)))
        self.label.add("三角形的周长")
        return self


class TriangleAreaMaxIs(BaseFunction):
    def solver(self, *args):
        tuoyuan = [value for _, value in self.known.items() if isinstance(value, BaseTuoYuan)]
        assert tuoyuan
        step1 = OvalCoeffs().solver(tuoyuan[0])
        step2 = OvalAbc().solver(*step1.output).output[0]
        a, b, c = step2.value
        self.output.append(BaseEq([2 * c * b / 2, args[1].sympify()]))
        # self.output.append(BasePoly(4*step2.value[0]))
        return self


class PolyMinIs(BaseFunction):
    def solver(self, *args):
        assert "cos" in str(args[0].value) and "acos" in str(args[0].value)
        tuoyuan = [value for _, value in self.known.items() if isinstance(value, BaseYuan)]
        assert tuoyuan
        step1 = OvalCoeffs().solver(tuoyuan[0])
        step2 = OvalAbc().solver(*step1.output).output[0]
        a, b, c = step2.value
        self.output.append(BaseEq([(a ** 2 - 2 * c ** 2) / a ** 2, args[1].sympify()]))
        return self


class ShuangQuZhouChang(BaseFunction):
    def solver(self, *args):
        a, b, c = args[0].value
        if "实轴" in args[1]:
            self.output.append(BasePoly(2 * a))
        elif "虚轴" in args[1]:
            self.output.append(BasePoly(2 * b))
        else:
            raise ValueError()
        self.label.add("双曲线的轴长")
        return self


class TuoYuanZhouChang(BaseFunction):
    def solver(self, *args):
        a, b, c = args[0].value
        if "长轴" in args[1]:
            self.output.append(BasePoly(2 * a))
        elif "短轴" in args[1]:
            self.output.append(BasePoly(2 * b))
        else:
            raise ValueError()
        self.label.add("椭圆的轴长")
        return self


class AnglePingFen(BaseFunction):
    def solver(self, *args):
        a1, a2, a3 = args[0].value
        nt = [nn for nn in args[1].value if nn not in args[0].value][0]
        obj = BaseGeoEq(["Angle(%s)" % ",".join([a1, a2, nt]), "Angle(%s)" % ",".join([a3, a2, nt])])
        self.output.append(obj)
        self.label.add("角平分线")
        return self


class TriangleWaiJieYuan(BaseFunction):
    def solver(self, *args):
        name = args[0].value
        points = [self.search(nn) for nn in name]
        points = BaseMultiple({"objs": points, "type": "points"})
        self.label.add("三角形的外接圆")
        return YuanFangCheng005().solver(points)


class GetPartial(BaseFunction):
    def solver(self, *args):
        if len(args) == 3:
            axis, graph, text = args[:3]
            if "y" in axis.value:
                if "上方" in text:
                    cond = BaseIneq(["y", ">", "0"])
                elif "下方" in text:
                    cond = BaseIneq(["y", "<", "0"])
        elif len(args) == 2:
            graph, text = args[:2]
            if "左支" in text:
                cond = BaseIneq(["x", "<", "0"])
            elif "右支" in text:
                cond = BaseIneq(["x", ">", "0"])

        obj = BasePartial(graph.value)
        obj.cond = cond
        self.output.append(obj)
        return self


if __name__ == '__main__':
    pass
